home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / libs / tsipp / tsipp.lha / tsipp3.0a / sippsrc / lightsource.c next >
Encoding:
C/C++ Source or Header  |  1992-11-02  |  10.5 KB  |  462 lines

  1. /**
  2.  ** sipp - SImple Polygon Processor
  3.  **
  4.  **  A general 3d graphic package
  5.  **
  6.  **  Copyright Equivalent Software HB  1992
  7.  **
  8.  ** This program is free software; you can redistribute it and/or modify
  9.  ** it under the terms of the GNU General Public License as published by
  10.  ** the Free Software Foundation; either version 1, or any later version.
  11.  ** This program is distributed in the hope that it will be useful,
  12.  ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  ** GNU General Public License for more details.
  15.  ** You can receive a copy of the GNU General Public License from the
  16.  ** Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  17.  **/
  18.  
  19. /**
  20.  ** lightsource.c - Functions that handles lightsources.
  21.  **/
  22.  
  23. #include <stdio.h>
  24. #include <math.h>
  25. #include <values.h>
  26.  
  27. #ifndef MAXFLOAT
  28. #   define MAXFLOAT 1.0e100
  29. #endif
  30.  
  31. #include <geometric.h>
  32. #include <lightsource.h>
  33. #include <sipp.h>
  34. #include <smalloc.h>
  35.  
  36.  
  37. Lightsource  *lightsrc_stack;  /* Stack of installed lightsources. */
  38.  
  39. extern int depthmap_size;
  40.  
  41. static int    rand_index = 0;
  42. static double rand_no[256];
  43.  
  44. static double shadow_sample();
  45.  
  46.  
  47. /*
  48.  * Create a new lightsource in the scene.
  49.  */
  50. Lightsource *
  51. lightsource_create(x, y, z, red, grn, blu, type)
  52.     double  x, y, z;
  53.     double  red, grn, blu;
  54.     int     type;
  55. {
  56.     Lightsource    *lp;
  57.     Dir_light_info *ip;
  58.  
  59.     if (type != LIGHT_DIRECTION && type != LIGHT_POINT) {
  60.         return NULL;
  61.     }
  62.  
  63.     lp = (Lightsource *)scalloc(1, sizeof(Lightsource));
  64.     ip = (Dir_light_info *)scalloc(1, sizeof(Dir_light_info));
  65.  
  66.     MakeVector(ip->dir, x, y, z);
  67.     if (type == LIGHT_DIRECTION) {
  68.         vecnorm(&ip->dir);
  69.     }
  70.     lp->info = (void *)ip;
  71.     
  72.     lp->type = type;
  73.     lp->color.red = red;
  74.     lp->color.grn = grn;
  75.     lp->color.blu = blu;
  76.     lp->active = TRUE;
  77.     lp->next = lightsrc_stack;
  78.     lp->shadow.active = FALSE;
  79.     lightsrc_stack = lp;
  80.  
  81.     return lp;
  82. }
  83.  
  84.  
  85. /*
  86.  * Change the position of a lightsource. If it is a directional
  87.  * lightsource it's direction is changed.
  88.  */
  89. void
  90. lightsource_put(lp, x, y, z)
  91.     Lightsource *lp;
  92.     double       x, y, z;
  93. {
  94.     if (lp->type != LIGHT_DIRECTION && lp->type != LIGHT_POINT) {
  95.         return;
  96.     }
  97.  
  98.     MakeVector(((Dir_light_info *)(lp->info))->dir, x, y, z);
  99.     if (lp->type == LIGHT_DIRECTION) {
  100.         vecnorm(&((Dir_light_info *)(lp->info))->dir);
  101.     }
  102. }
  103.     
  104.  
  105. /*
  106.  * Define a new spotlight in the scene.
  107.  */
  108. Lightsource *
  109. spotlight_create(x, y, z, to_x, to_y, to_z, fov, red, grn, blu, type, shadows)
  110.     double  x, y, z;
  111.     double  to_x, to_y, to_z;
  112.     double  fov;
  113.     double  red, grn, blu;
  114.     int     type;
  115.     bool    shadows;
  116. {
  117.     Lightsource     *lp;
  118.     Spot_light_info *sp;
  119.     Vector           tmp;
  120.  
  121.     if (type != SPOT_SHARP && type != SPOT_SOFT) {
  122.         return NULL;
  123.     }
  124.  
  125.     lp = (Lightsource *)scalloc(1, sizeof(Lightsource));
  126.     sp = (Spot_light_info *)scalloc(1, sizeof(Spot_light_info));
  127.  
  128.     MakeVector(sp->pos, x, y, z);
  129.     MakeVector(sp->point, to_x, to_y, to_z);
  130.     VecSub(sp->dir, sp->point, sp->pos);
  131.     vecnorm(&sp->dir);
  132.     sp->cos_fov = cos(fov * M_PI / 180.0 * 0.5);
  133.     lp->info = (void *)sp;
  134.     
  135.     lp->shadow.fov_factor = tan(fov * M_PI / 180.0 * 0.5);
  136.     lp->shadow.active = shadows;
  137.     lp->shadow.d_map = NULL;
  138.  
  139.     lp->type = type;
  140.     lp->color.red = red;
  141.     lp->color.grn = grn;
  142.     lp->color.blu = blu;
  143.     lp->active = TRUE;
  144.     lp->next = lightsrc_stack;
  145.     lightsrc_stack = lp;
  146.  
  147.     return lp;
  148. }
  149.  
  150.  
  151. /*
  152.  * Remove the lightsource LIGHT from the list of lights and free all 
  153.  * resources attached to it.
  154.  */
  155. void
  156. light_destruct(light)
  157.     Lightsource   *light;
  158. {
  159.     Lightsource  * lght;
  160.  
  161.     /* First,  we must remove the light from the list of active lights. */
  162.     while (lightsrc_stack == light)
  163.     lightsrc_stack = lightsrc_stack->next;
  164.  
  165.     lght = lightsrc_stack;
  166.     while (lght != NULL) {
  167.     if (lght->next == light)
  168.         lght->next = lght->next->next;
  169.     else
  170.         lght = lght->next;
  171.     }
  172.  
  173.     sfree(light->info);
  174.     sfree(light);
  175. }
  176.  
  177.  
  178. /*
  179.  * Change the position of a spotlight.
  180.  */
  181. void 
  182. spotlight_pos(lp, x, y, z)
  183.     Lightsource *lp;
  184.     double       x, y, z;
  185. {
  186.     Spot_light_info *sp;
  187.  
  188.     if (lp->type != SPOT_SOFT && lp->type != SPOT_SHARP) {
  189.         return;
  190.     }
  191.  
  192.     sp = (Spot_light_info *)(lp->info);
  193.     MakeVector(sp->pos, x, y, z);
  194.     VecSub(sp->dir, sp->point, sp->pos);
  195.     vecnorm(&sp->dir);
  196. }
  197.  
  198.  
  199. /*
  200.  * Change the point a spotlight is shining at.
  201.  */
  202. void 
  203. spotlight_at(lp, x, y, z)
  204.     Lightsource *lp;
  205.     double       x, y, z;
  206. {
  207.     Spot_light_info *sp;
  208.  
  209.     if (lp->type != SPOT_SOFT && lp->type != SPOT_SHARP) {
  210.         return;
  211.     }
  212.  
  213.     sp = (Spot_light_info *)(lp->info);
  214.     MakeVector(sp->point, x, y, z);
  215.     VecSub(sp->dir, sp->point, sp->pos);
  216.     vecnorm(&sp->dir);
  217. }
  218.  
  219.  
  220. /*
  221.  * Change the opening angle of a spotlight.
  222.  */
  223. extern void          spotlight_opening();
  224. void 
  225. spotlight_opening(lp, fov)
  226.     Lightsource *lp;
  227.     double       fov;
  228. {
  229.     if (lp->type != SPOT_SOFT && lp->type != SPOT_SHARP) {
  230.         return;
  231.     }
  232.  
  233.     ((Spot_light_info *)(lp->info))->cos_fov = cos(fov * M_PI / 180.0 * 0.5);
  234. }
  235.  
  236.  
  237. /*
  238.  * Turn on or off shadow generation from a spotlight.
  239.  */
  240. void 
  241. spotlight_shadows(lp, flag)
  242.     Lightsource *lp;
  243.     bool         flag;
  244. {
  245.     if (lp->type != SPOT_SOFT && lp->type != SPOT_SHARP) {
  246.         return;
  247.     }
  248.  
  249.     lp->shadow.active = flag;
  250. }
  251.  
  252.     
  253. /*
  254.  * Set the color of the light from a lightsource or a spotlight.
  255.  */
  256. void light_color(lp, red, grn, blu)
  257.     Lightsource *lp;
  258.     double       red, grn, blu;
  259. {
  260.     lp->color.red = red;
  261.     lp->color.grn = grn;
  262.     lp->color.blu = blu;
  263. }
  264.     
  265.  
  266. /*
  267.  * Turn a lightsource or spotlight on or off.
  268.  */
  269. void 
  270. light_active(lp, flag)
  271.     Lightsource *lp;
  272.     bool         flag;
  273. {
  274.     lp->active = flag;
  275. }
  276.  
  277.  
  278. /*
  279.  * Evaluate how much light from the lightsource LP thas is falling
  280.  * on the point POS. Type of lightsource and shadows are taken into
  281.  * account.
  282.  * In VEC we return a vector pointing from POS to LP.
  283.  */
  284. double
  285. light_eval(lp, pos, vec)
  286.     Lightsource *lp;
  287.     Vector      *pos;
  288.     Vector      *vec;
  289. {
  290.     double fov_factor;
  291.  
  292.     switch (lp->type) {
  293.       case LIGHT_DIRECTION:
  294.         VecCopy(*vec, ((Dir_light_info *)(lp->info))->dir);
  295.         return 1.0;
  296.  
  297.       case LIGHT_POINT:
  298.         VecSub(*vec, ((Dir_light_info *)(lp->info))->dir, *pos);
  299.         vecnorm(vec);
  300.         return 1.0;
  301.  
  302.       case SPOT_SOFT:
  303.         VecSub(*vec, *pos, ((Spot_light_info *)(lp->info))->pos);
  304.         vecnorm(vec);
  305.  
  306.         fov_factor = VecDot(*vec, ((Spot_light_info *)(lp->info))->dir);
  307.         if (fov_factor <= 0.0
  308.             || fov_factor < ((Spot_light_info *)(lp->info))->cos_fov)
  309.         {
  310.             VecNegate(*vec);
  311.             return 0.0;
  312.  
  313.         } else {
  314.             fov_factor = (cos((1.0 - fov_factor) * M_PI 
  315.                               / (1.0 - ((Spot_light_info *)
  316.                                         (lp->info))->cos_fov))  
  317.                           * 0.5 + 0.5);
  318.             if (lp->shadow.active && lp->shadow.d_map) {
  319.                 VecNegate(*vec);
  320.                 return fov_factor * shadow_sample(&lp->shadow, pos);
  321.  
  322.             } else {
  323.                 VecNegate(*vec);
  324.                 return fov_factor;
  325.             }
  326.         } 
  327.  
  328.       case SPOT_SHARP:
  329.         VecSub(*vec, *pos, ((Spot_light_info *)(lp->info))->pos);
  330.         vecnorm(vec);
  331.  
  332.         if (VecDot(*vec, ((Spot_light_info *)(lp->info))->dir) 
  333.             < ((Spot_light_info *)(lp->info))->cos_fov) 
  334.         {
  335.             VecNegate(*vec);
  336.             return 0.0;
  337.  
  338.         } else if (lp->shadow.active && lp->shadow.d_map) {
  339.             VecNegate(*vec);
  340.             return shadow_sample(&lp->shadow, pos);
  341.  
  342.         } else {
  343.             VecNegate(*vec);
  344.             return 1.0;
  345.         }
  346.     }
  347. }
  348.  
  349.  
  350. /*
  351.  * Sample a depth map and do percentage closer filtering to
  352.  * see how much shadowed POS is.
  353.  */
  354. #define BOXRES  0.002
  355. static double
  356. shadow_sample(sh, pos)
  357.     Shadow_info *sh;
  358.     Vector      *pos;
  359. {
  360.     Vector   lp_view;
  361.     int      lit;
  362.     int      ns;
  363.     int      x, y;
  364.     int      i, j;
  365.     double   lu, hu;
  366.     double   lv, hv;
  367.     double   xmin, ymin;
  368.     double   boxres;
  369.     double   ds, js;
  370.     double   persp;
  371.  
  372.     point_transform(&lp_view, pos, &sh->matrix);
  373.     persp = lp_view.z * sh->fov_factor;
  374.     lp_view.x = (lp_view.x * depthmap_size * 0.5 / persp
  375.                  + depthmap_size * 0.5);
  376.     lp_view.y = (lp_view.y * depthmap_size * 0.5 / persp
  377.                  + depthmap_size * 0.5);
  378.     
  379.     boxres = BOXRES * depthmap_size;
  380.     lu = floor(lp_view.x - boxres);
  381.     lv = floor(lp_view.y - boxres);
  382.     hu = ceil(lp_view.x + boxres);
  383.     hv = ceil(lp_view.y + boxres);
  384.     if (lu >= depthmap_size || hu < 0.0
  385.         || lv >= depthmap_size || hv < 0.0) 
  386.     {
  387.         return 1.0;
  388.     }
  389.  
  390.     ns = (int)(boxres * 2.0 + 0.5);
  391.  
  392.     ds = 2.0 * boxres / ns;
  393.     js = ds * 0.5;
  394.  
  395.     xmin = lp_view.x - boxres + js;
  396.     ymin = lp_view.y - boxres + js;
  397.  
  398.     lit = ns * ns;
  399.     for (i = 0, lp_view.x = xmin; i < ns; i++, lp_view.x += ds) {
  400.         for (j = 0, lp_view.y = ymin; j < ns; j++, lp_view.y += ds) {
  401.             rand_index = (rand_index + 1) & 255;
  402.             x = lp_view.x + rand_no[rand_index] * js;
  403.             rand_index = (rand_index + 1) & 255;
  404.             y = lp_view.y + rand_no[rand_index] * js;
  405.             if (x >= 0 && x < depthmap_size 
  406.                 && y >= 0 && y < depthmap_size) {
  407.                 if (lp_view.z > (sh->d_map[(depthmap_size - 1 - y) 
  408.                                            * depthmap_size + x] 
  409.                                  + sh->bias)) {
  410.                     lit--;
  411.                 }
  412.             }
  413.         }
  414.         
  415.     }
  416.  
  417.    return (double)lit / (double)(ns * ns);
  418. }
  419.  
  420.  
  421. /*
  422.  * Create and initialize depthmaps for all lightsources
  423.  * that have their shadow generation activated.
  424.  */
  425. void
  426. depthmaps_create()
  427. {
  428.     Lightsource *lp;
  429.     int          i;
  430.  
  431.     for (i = 0; i < 256; i++) {
  432.         rand_no[i] = (RANDOM() + 1.0) * 0.5;
  433.     }
  434.     rand_index = 0;
  435.     for (lp = lightsrc_stack; lp != NULL; lp = lp->next) {
  436.         if (lp->shadow.active) {
  437.             lp->shadow.d_map = (float *)smalloc(depthmap_size * depthmap_size
  438.                                                 * sizeof(float));
  439.             for (i = 0; i < depthmap_size * depthmap_size; i++) {
  440.                 lp->shadow.d_map[i] = (float)MAXFLOAT;
  441.             }
  442.         }
  443.     }
  444. }
  445.    
  446.  
  447. /*
  448.  * Release the memory used by the depthmaps.
  449.  */
  450. void
  451. depthmaps_destruct()
  452. {
  453.     Lightsource *lp;
  454.  
  455.     for (lp = lightsrc_stack; lp != NULL; lp = lp->next) {
  456.         if (lp->shadow.active && lp->shadow.d_map != NULL) {
  457.             sfree(lp->shadow.d_map);
  458.             lp->shadow.d_map = NULL;
  459.         }
  460.     }
  461. }
  462.